namespace EyeOpen.Data.DataAnnotations.Nhibernate
{
	using System;
	using System.Collections.Generic;

	using EyeOpen.Linq;

	using NHibernate.Cfg.MappingSchema;
	using NHibernate.Mapping.ByCode;

	public class ModelAnnotationsMapper 
		: ModelMapper
	{
		private readonly IDictionary<Strategy, Type> strategyTypeDictionary =
			new Dictionary<Strategy, Type> 
				{
					{ Strategy.TablePerClass, typeof(ClassAnnotationsMap<>) }
				};

		private readonly IDictionary<Type, Strategy> entityTypeList =
			new Dictionary<Type, Strategy>();

		public ModelAnnotationsMapper()
		{
		}

		public ModelAnnotationsMapper(IDictionary<Strategy, Type> strategyTypeDictionary)
		{
			this.strategyTypeDictionary = strategyTypeDictionary;
		}

		public void Map(Type[] types)
		{
			types
				.ForEach(x => Map(x));
		}

		public ModelAnnotationsMapper Map<T>(Strategy strategy = Strategy.TablePerClass)
		{
			return Map(typeof(T), strategy);
		}

		public ModelAnnotationsMapper Map(Type type, Strategy strategy = Strategy.TablePerClass)
		{
			entityTypeList.Add(type, strategy);
			return this;
		}

		public HbmMapping CompileMapping()
		{
			entityTypeList
				.ForEach(AddMapping);

			return
				CompileMappingFor(entityTypeList.Keys);
		}

		protected virtual void AddMapping(KeyValuePair<Type, Strategy> obj)
		{
			var annotationType = GetAnnotationType(obj);

			AddMapping((IConformistHoldersProvider)Activator.CreateInstance(annotationType));
		}

		protected virtual Type GetAnnotationType(KeyValuePair<Type, Strategy> type)
		{
			var annotationType = strategyTypeDictionary[type.Value];

			if (annotationType.IsGenericType)
			{
				annotationType = annotationType.MakeGenericType(type.Key);
			}

			return annotationType;
		}
	}
}